package model;

import java.util.ArrayList;
import java.util.TreeMap;

import exceptions.ExecaoMnemonicoInexistente;
import exceptions.ExecaoMontador;
import exceptions.ExecaoNumeroForaDosLimites;
import exceptions.ExecaoRegistradorInexistente;
import exceptions.ExecaoRotuloNaoDefinido;
import exceptions.ExecaoRotuloSemInstrucao;

import basics.ConversaoDeBases;

public class Montador {

	private ArrayList<Instrucao> instrucoes;
	private TreeMap<String, Long> rotulos;
	private TreeMap<Long, String> rotulosInverso;

	private TreeMap<String, String> mapaOp;
	private TreeMap<String, Integer> mapaTipoInstrucao;
	private TreeMap<String, String> mapaFunction;

	private TreeMap<String, String> mapaRegistradores;

	// Constantes internas
	private final static int TIPO_R = 0;
	private final static int TIPO_I = 1;
	private final static int TIPO_J = 2;

	// Posição incial da memória em que é colocado o programa
	private long posicaoMemoria = 0;

	protected Montador() {

		instrucoes = new ArrayList<Instrucao>();
		rotulos = new TreeMap<String, Long>();
		rotulosInverso = new TreeMap<Long, String>();

		mapaOp = new TreeMap<String, String>();
		mapaTipoInstrucao = new TreeMap<String, Integer>();
		mapaFunction = new TreeMap<String, String>();

		mapaRegistradores = new TreeMap<String, String>();

		criaMapas();
	}

	private boolean ehComentarioOuVazio(String str) {
		if ((str.startsWith("#")) || (str.equals("")))
			return true;
		return false;
	}

	private String removeEspacosIniciaisBrancos(String str) {
		return str.replaceAll("\t", " ").replaceAll("^\\s+", "");

	}

	// separaRotuloDoComando[0] é o rótulo e separaRotuloDoComando[1] é o
	// comando sem o rótulo
	private String[] separaRotuloDoComando(String comando) {
		String aux[];
		aux = comando.split(":");

		if (aux.length > 1) {
			// Remove os espaçamentos depois do rótulo
			aux[1] = this.removeEspacosIniciaisBrancos(aux[1]); // Comando sem
																// rótulo
		}
		return aux;
	}

	protected ArrayList<LinhaDeExecucao> obtemInstrucoes(Memoria memoria, ArrayList<String> assemblyCode) throws ExecaoMontador {

		Instrucao instrucao;
		ArrayList<LinhaDeExecucao> listaDeExecucao =
				new ArrayList<LinhaDeExecucao>();

		String str;

		String aux[];

		String comando;
		String rotulo;
		long enderecoDaInstrucao = posicaoMemoria;

		// Variáveis auxiliares para armazenar a conversão de uma instrução e um
		// endereço numa string binária
		String[] instrucaoString = new String[4];
		String enderecoString;
		int i = 0;

		try {
			// Lê linha por linha do arquivo definindo as instruções
			for (i = 0; i < assemblyCode.size(); i++) {

				// Lê linha
				str = assemblyCode.get(i);

				// Remove os espaços inicias iniciados com espaçamentos,
				// tabulações,
				// etc.
				str = removeEspacosIniciaisBrancos(str);

				// Se esta linha não for em branco ou não for um comentário,
				// então
				// tentamos obter a instrunção referente ao comando
				if (!ehComentarioOuVazio(str)) {

					aux = separaRotuloDoComando(str);

					// Se a linha possui um rótulo
					if (str.contains(":")) {

						// define os rótulos
						rotulo = aux[0];

						// Se a instrução do rótulo está em outra linha
						while ((i <= assemblyCode.size())
								&& (removeEspacosIniciaisBrancos(aux[1]).equals(""))) {

							// incrementa linha
							i++;
							aux[1] = assemblyCode.get(i);

							if (aux[1].contains(":")) {
								// Aqui deve lançar uma exceção.
								throw new ExecaoRotuloSemInstrucao();
							}
						}

						rotulos.put(rotulo, Long.valueOf(enderecoDaInstrucao));
						rotulosInverso.put(Long.valueOf(enderecoDaInstrucao), rotulo);
						aux[0] = removeEspacosIniciaisBrancos(aux[1]); // Atualiza
																		// array
																		// auxiliar

					}

					// tenta definir a instrução
					comando = aux[0];
					comando = comando.replaceAll(",\\s+", ","); // Remove os
																// espaços
																// depois da
																// vírgula

					comando = expandeInstrucao(comando, assemblyCode, i);
					instrucao = defineInstrucao(comando, enderecoDaInstrucao);

					instrucoes.add(instrucao); // adiciona a instrução no array

					listaDeExecucao.add(new LinhaDeExecucao(0, null, comando.replaceAll(",", ", ")));

					enderecoDaInstrucao += 4; // incrementa o número da linha
					// referente a respectiva instrução
					// lida
				}
			}
		} catch (ExecaoMontador e) {
			e.setLinha(i + 1);
			throw e;
		}

		// Define os rótulos das instruções
		instrucoes = definirRotulos(instrucoes);
		Instrucao inst = null;
		String setRotulo = "";
		for (i = 0; i < instrucoes.size(); i++) {
			inst = instrucoes.get(i);
			setRotulo = rotulosInverso.get(Long.valueOf(i * 4));
			if (setRotulo != null)
				listaDeExecucao.get(i).setRotulo(setRotulo);
			else
				listaDeExecucao.get(i).setRotulo("");
			
			listaDeExecucao.get(i).setEnderecoDecimal(i * 4);
			listaDeExecucao.get(i).setCodigoMaquina(inst.getInstrucao());

			// A palavra possui 32bits e um pedaço da memória possui 1byte =
			// 8bits.

			// Define o valor da memória no endereço especificado
			instrucaoString[0] = inst.getInstrucao().substring(0, 8);
			enderecoString = ConversaoDeBases.DecToBin(inst.getEndereco());
			memoria.set(enderecoString, instrucaoString[0]);

			instrucaoString[1] = inst.getInstrucao().substring(8, 16);
			enderecoString =
					ConversaoDeBases.DecToBin(inst.getEndereco()
							+ Integer.valueOf(1));
			memoria.set(enderecoString, instrucaoString[1]);

			instrucaoString[2] = inst.getInstrucao().substring(16, 24);
			enderecoString =
					ConversaoDeBases.DecToBin(inst.getEndereco()
							+ Integer.valueOf(2));
			memoria.set(enderecoString, instrucaoString[2]);

			instrucaoString[3] = inst.getInstrucao().substring(24, 32);
			enderecoString =
					ConversaoDeBases.DecToBin(inst.getEndereco()
							+ Integer.valueOf(3));
			memoria.set(enderecoString, instrucaoString[3]);
		}

		return listaDeExecucao;
	}

	private String expandeInstrucao(String comando, ArrayList<String> assemblyCode, int i) throws ExecaoNumeroForaDosLimites {
		// TODO Auto-generated method stub
		String[] split = comando.split("\\s+");
		String mnemonico = split[0];
		String[] argumentos;
		try {

			if (split.length > 1) {
				argumentos = split[1].split(",");

				if (mnemonico.equals("move")) {
					comando =
							"add " + argumentos[0] + ",$zero," + argumentos[1];
					assemblyCode.set(i, comando);

				} else if (mnemonico.equals("addi") || mnemonico.equals("slti")
						|| mnemonico.equals("andi") || mnemonico.equals("ori")) {

					if (((((long) Long.valueOf(argumentos[2])) > ((long) Math.pow(2, 16) - 1)))
							|| ((((long) Long.valueOf(argumentos[2])) < ((long) -Math.pow(2, 16))))) {

						comando =
								"lui $at,"
										+ ConversaoDeBases.binToDecSigned(ConversaoDeBases.DecToBin(argumentos[2]).substring(0, 16));
						assemblyCode.set(i, comando);

						assemblyCode.add(i + 1, "ori $at,$at,"
								+ ConversaoDeBases.binToDecSigned("0000000000000000"
										+ ConversaoDeBases.DecToBin(argumentos[2]).substring(16)));
						assemblyCode.add(i + 2, mnemonico.replaceAll("i", "")
								+ " " + argumentos[0] + "," + argumentos[1]
								+ ",$at");
					} else if (((((long) Long.valueOf(argumentos[2])) > ((long) Math.pow(2, 32) - 1)))
							|| ((((long) Long.valueOf(argumentos[2])) < ((long) -Math.pow(2, 32))))) {
						throw new ExecaoNumeroForaDosLimites();
					}

				} else if ((mnemonico.equals("sltiu"))
						|| (mnemonico.equals("addiu"))) {

					if ((((long) Long.valueOf(argumentos[2])) > ((long) Math.pow(2, 16)))) {
						comando =
								"lui $at,"
										+ ConversaoDeBases.binToDecUnsigned(ConversaoDeBases.DecToBin(argumentos[2]).substring(0, 16));
						assemblyCode.set(i, comando);

						assemblyCode.add(i + 1, "ori $at,$at,"
								+ ConversaoDeBases.binToDecUnsigned("0000000000000000"
										+ ConversaoDeBases.DecToBin(argumentos[2]).substring(16)));
						assemblyCode.add(i + 2, mnemonico.replaceAll("i", "")
								+ " " + argumentos[0] + "," + argumentos[1]
								+ ",$at");
					} else if ((((long) Long.valueOf(argumentos[2])) > ((long) Math.pow(2, 32)))) {
						throw new ExecaoNumeroForaDosLimites();
					}
				}
			}
		} catch (NumberFormatException e) {
			throw new ExecaoNumeroForaDosLimites();
		}

		return comando;

	}

	private Instrucao defineInstrucao(String comando, long enderecoDaIntrucao) throws ExecaoMnemonicoInexistente, ExecaoRegistradorInexistente {

		Instrucao instrucao = null;
		int tipoInstrucao;
		String mnemonico, atributosDaInstrucao, op;
		boolean tipoDesvio = false; // se uma instrução do tipoI é do tipo de
									// desvio condicional

		String rs = "00000";
		String rt = "00000";
		String rd = "00000";
		String shamt = "00000";
		String function = "000000";
		String imediatoOuRotulo = "0000000000000000";
		String rotulo = "00000000000000000000000000";

		String aux[]; // Variável auxiliar

		aux = comando.split("\\s+");
		mnemonico = aux[0]; // obtêm o mnemônico

		// Obtêm o op referente ao mnemônico

		op = mapaOp.get(mnemonico);
		if (op == null)
			throw new ExecaoMnemonicoInexistente();

		// obtêm o tipo da intrução referente ao op
		tipoInstrucao = ((int) mapaTipoInstrucao.get(op));

		switch (tipoInstrucao) {

		case TIPO_R:

			// Instância instrução como do tipo R
			instrucao = new TipoR();

			instrucao.setEndereco(Long.valueOf(enderecoDaIntrucao));
			instrucao.setOp(op);
			function = mapaFunction.get(mnemonico);

			if (function == null)
				throw new ExecaoMnemonicoInexistente();

			((TipoR) instrucao).setFunction(function);

			// Function é o break ou o syscall ou Halt
			if (aux.length == 1) {
				rs = "00000";
				rt = "00000";
				rd = "00000";
				shamt = "00000";

				((TipoR) instrucao).setRs(rs);
				((TipoR) instrucao).setRt(rt);
				((TipoR) instrucao).setRd(rd);
				((TipoR) instrucao).setShamt(shamt);

				return instrucao;
			}

			// Os atributos da instrução são os registradores, valores imediatos
			// e endereços
			atributosDaInstrucao = aux[1];

			// Quebra a instrução sem o mnemônico em partes
			aux = atributosDaInstrucao.split(",");

			// Instruções do tipo rd, rs, rt
			if ((mnemonico.equals("add")) || (mnemonico.equals("addu"))
					|| (mnemonico.equals("and")) || (mnemonico.equals("nor"))
					|| (mnemonico.equals("or")) || (mnemonico.equals("slt"))
					|| (mnemonico.equals("sltu")) || (mnemonico.equals("sub"))
					|| (mnemonico.equals("subu")) || (mnemonico.equals("xor"))) {
				rd = mapaRegistradores.get(aux[0]);
				rs = mapaRegistradores.get(aux[1]);
				rt = mapaRegistradores.get(aux[2]);
				shamt = "00000";
			}

			// Instruções do tipo rd, rt, rs
			else if ((mnemonico.equals("sllv")) || (mnemonico.equals("srav"))
					|| (mnemonico.equals("srlv"))) {
				rd = mapaRegistradores.get(aux[0]);
				rt = mapaRegistradores.get(aux[1]);
				rs = mapaRegistradores.get(aux[2]);
				shamt = "00000";
			}

			// Instruções do tipo rd, rt, sa

			else if ((mnemonico.equals("sll")) || (mnemonico.equals("sra"))
					|| (mnemonico.equals("srl"))) {
				rd = mapaRegistradores.get(aux[0]);
				rt = mapaRegistradores.get(aux[1]);
				rs = "00000";

				shamt = ConversaoDeBases.DecToBin(aux[2], 5);
			}
			
			// Instruções do tipo rs, rt
			else if ((mnemonico.equals("div")) || (mnemonico.equals("divu"))
					|| (mnemonico.equals("mult"))
					|| (mnemonico.equals("multu"))) {
				rs = mapaRegistradores.get(aux[0]);
				rt = mapaRegistradores.get(aux[1]);
				rd = "00000";
				shamt = "00000";
			}

			// Instruções do tipo rd, rs
			else if (mnemonico.equals("jalr")) {
				rd = mapaRegistradores.get(aux[0]);
				rs = mapaRegistradores.get(aux[1]);
				rt = "00000";
				shamt = "00000";
			}

			// Instruções do tipo rs, rt
			else if ((mnemonico.equals("div")) || (mnemonico.equals("divu"))
					|| (mnemonico.equals("mult"))
					|| (mnemonico.equals("multu"))) {
				rs = mapaRegistradores.get(aux[0]);
				rt = mapaRegistradores.get(aux[1]);
				rd = "00000";
				shamt = "00000";
			}

			// Instruções do tipo rs
			else if ((mnemonico.equals("jr")) || (mnemonico.equals("mthi"))
					|| (mnemonico.equals("mtlo"))) {
				rs = mapaRegistradores.get(aux[0]);
				rt = "00000";
				rd = "00000";
				shamt = "00000";
			}

			// Instruções do tipo rd
			else if ((mnemonico.equals("mfhi")) || (mnemonico.equals("mflo"))) {
				rd = mapaRegistradores.get(aux[0]);
				rs = "00000";
				rt = "00000";
				shamt = "00000";
			}

			if (rd == null || rs == null || rt == null)
				throw new ExecaoRegistradorInexistente();

			// Seta os parâmetros na instrução
			((TipoR) instrucao).setRs(rs);
			((TipoR) instrucao).setRt(rt);
			((TipoR) instrucao).setRd(rd);
			((TipoR) instrucao).setShamt(shamt);

			break;

		case TIPO_I:
			instrucao = new TipoI();

			instrucao.setEndereco(Long.valueOf(enderecoDaIntrucao));
			instrucao.setOp(op);

			// Os atributos da instrução são os registradores, valores imediatos
			// e endereços
			atributosDaInstrucao = aux[1];

			// Quebra a instrução sem o mnemônico em partes
			aux = atributosDaInstrucao.split(",");

			// Instruções do tipo rt, rs, imediato
			if ((mnemonico.equals("addi")) || (mnemonico.equals("addiu"))
					|| (mnemonico.equals("andi")) || (mnemonico.equals("ori"))
					|| (mnemonico.equals("slti"))
					|| (mnemonico.equals("sltiu"))
					|| (mnemonico.equals("xori"))) {
				rt = mapaRegistradores.get(aux[0]);
				rs = mapaRegistradores.get(aux[1]);
				imediatoOuRotulo = ConversaoDeBases.DecToBin(aux[2], 16);
			}

			// Instruções do tipo rs, rt, rotulo
			else if ((mnemonico.equals("beq")) || (mnemonico.equals("bne"))) {
				rs = mapaRegistradores.get(aux[0]);
				rt = mapaRegistradores.get(aux[1]);
				imediatoOuRotulo = aux[2];
				tipoDesvio = true;
			}

			// Instruções do tipo rt, imediato
			else if (mnemonico.equals("lui")) {
				rt = mapaRegistradores.get(aux[0]);
				rs = "00000";
				imediatoOuRotulo = ConversaoDeBases.DecToBin(aux[1], 16);
			}

			// Instruções do tipo rs, rotulo
			else if ((mnemonico.equals("bgez")) || (mnemonico.equals("bgtz"))
					|| (mnemonico.equals("blez")) || (mnemonico.equals("bltz"))) {
				rs = mapaRegistradores.get(aux[0]);
				rt = "00000";
				imediatoOuRotulo = aux[1];
				tipoDesvio = true;
			}

			// Instruções do tipo rt, imediato(rs)
			else if ((mnemonico.equals("lb")) || (mnemonico.equals("lbu"))
					|| (mnemonico.equals("lh")) || (mnemonico.equals("lhu"))
					|| (mnemonico.equals("sb")) || (mnemonico.equals("sh"))
					|| (mnemonico.equals("lw")) || (mnemonico.equals("lwcl"))
					|| (mnemonico.equals("sh")) || (mnemonico.equals("sw"))
					|| (mnemonico.equals("swcl"))) {
				rt = mapaRegistradores.get(aux[0]);
				aux[1] = aux[1].replaceAll("\\)", "");
				aux = aux[1].split("\\(");
				imediatoOuRotulo = ConversaoDeBases.DecToBin(aux[0], 16);
				rs = mapaRegistradores.get(aux[1]);
			}

			if (rs == null || rt == null)
				throw new ExecaoRegistradorInexistente();
			((TipoI) instrucao).setRs(rs);
			((TipoI) instrucao).setRt(rt);
			((TipoI) instrucao).setImediato(imediatoOuRotulo);
			((TipoI) instrucao).setTipoDesvio(tipoDesvio);

			break;

		case TIPO_J:

			// Os atributos da instrução são os registradores, valores imediatos
			// e endereços
			atributosDaInstrucao = aux[1];

			instrucao = new TipoJ();

			instrucao.setEndereco(Long.valueOf(enderecoDaIntrucao));
			instrucao.setOp(op);

			rotulo = atributosDaInstrucao;
			((TipoJ) instrucao).setRotuloDeDesvio(rotulo);
			break;
		}

		return instrucao; // Se não é uma instrução válida
	}

	protected ArrayList<Instrucao> definirRotulos(ArrayList<Instrucao> instrucoes) throws ExecaoRotuloNaoDefinido {

		String rotuloAtualizadao;
		Long auxiliar;
		try {
			for (Instrucao instrucao : instrucoes) {

				// Desvio relativo ao PC
				if ((instrucao instanceof TipoI)
						&& ((TipoI) instrucao).isTipoDesvio()) {
					auxiliar =
							this.rotulos.get(((TipoI) instrucao).getImediato());

					rotuloAtualizadao = Long.toString(auxiliar);
					rotuloAtualizadao =
							Long.toString(Long.valueOf(rotuloAtualizadao)
									- (((TipoI) instrucao).getEndereco() + 4));

					rotuloAtualizadao =
							ConversaoDeBases.DecToBin(rotuloAtualizadao, 16);

					((TipoI) instrucao).setImediato(rotuloAtualizadao);
				}

				// Desvio incondicional
				if (instrucao instanceof TipoJ) {
					auxiliar =
							((long) this.rotulos.get(((TipoJ) instrucao).getRotuloDeDesvio())) / 4;

					rotuloAtualizadao = Long.toString(auxiliar);
					rotuloAtualizadao =
							ConversaoDeBases.DecToBin(rotuloAtualizadao, 26);

					((TipoJ) instrucao).setRotuloDeDesvio(rotuloAtualizadao);
				}
			}
		} catch (NullPointerException e) {
			throw new ExecaoRotuloNaoDefinido();
		}

		return instrucoes;
	}

	protected long getPosicaoMemoria() {
		return posicaoMemoria;
	}

	private void criaMapas() {
		criaMapaOp();
		criaMapaFunction();
		mapeiaTipoDaInstrucao();
		criaMapaRegistradores();
	}

	private void criaMapaOp() {
		// Tipo R
		mapaOp.put("add", "000000");
		mapaOp.put("addu", "000000");
		mapaOp.put("and", "000000");
		mapaOp.put("break", "000000");
		mapaOp.put("div", "000000");
		mapaOp.put("divu", "000000");
		mapaOp.put("jalr", "000000");
		mapaOp.put("jr", "000000");
		mapaOp.put("mfhi", "000000");
		mapaOp.put("mflo", "000000");
		mapaOp.put("mthi", "000000");
		mapaOp.put("mtlo", "000000");
		mapaOp.put("mult", "000000");
		mapaOp.put("multu", "000000");
		mapaOp.put("nor", "000000");
		mapaOp.put("or", "000000");
		mapaOp.put("sll", "000000");
		mapaOp.put("sllv", "000000");
		mapaOp.put("slt", "000000");
		mapaOp.put("sltu", "000000");
		mapaOp.put("sra", "000000");
		mapaOp.put("srav", "000000");
		mapaOp.put("srl", "000000");
		mapaOp.put("srlv", "000000");
		mapaOp.put("sub", "000000");
		mapaOp.put("subu", "000000");
		mapaOp.put("syscall", "000000");
		mapaOp.put("xor", "000000");

		// Halt
		mapaOp.put("halt", "000000");

		// Tipo I
		mapaOp.put("addi", "001000");
		mapaOp.put("addiu", "001001");
		mapaOp.put("andi", "001100");
		mapaOp.put("beq", "000100");
		mapaOp.put("bgez", "000001");
		mapaOp.put("bgtz", "000111");
		mapaOp.put("blez", "000110");
		mapaOp.put("bltz", "000001");
		mapaOp.put("bne", "000101");
		mapaOp.put("lb", "100000");
		mapaOp.put("lbu", "100100");
		mapaOp.put("lh", "100001");
		mapaOp.put("lhu", "100101");
		mapaOp.put("lui", "001111");
		mapaOp.put("lw", "100011");
		mapaOp.put("lwcl", "110001");
		mapaOp.put("ori", "001101");
		mapaOp.put("sb", "101000");
		mapaOp.put("slti", "001010");
		mapaOp.put("sltiu", "001011");
		mapaOp.put("sh", "101001");
		mapaOp.put("sw", "101011");
		mapaOp.put("swcl", "111001");
		mapaOp.put("xori", "001110");

		// Tipo J
		mapaOp.put("j", "000010");
		mapaOp.put("jal", "000011");

	}

	private void criaMapaFunction() {

		mapaFunction.put("add", "100000");
		mapaFunction.put("addu", "100001");
		mapaFunction.put("and", "100100");
		mapaFunction.put("break", "001101");
		mapaFunction.put("div", "011010");
		mapaFunction.put("divu", "011011");
		mapaFunction.put("jalr", "001001");
		mapaFunction.put("jr", "001000");
		mapaFunction.put("mfhi", "010000");
		mapaFunction.put("mflo", "010010");
		mapaFunction.put("mthi", "010001");
		mapaFunction.put("mtlo", "010011");
		mapaFunction.put("mult", "011000");
		mapaFunction.put("multu", "011001");
		mapaFunction.put("nor", "100111");
		mapaFunction.put("or", "100101");
		mapaFunction.put("sll", "000000");
		mapaFunction.put("sllv", "000100");
		mapaFunction.put("slt", "101010");
		mapaFunction.put("sltu", "101011");
		mapaFunction.put("sra", "000011");
		mapaFunction.put("srav", "000111");
		mapaFunction.put("srl", "000010");
		mapaFunction.put("srlv", "000110");
		mapaFunction.put("sub", "100010");
		mapaFunction.put("subu", "100011");
		mapaFunction.put("syscall", "001100");
		mapaFunction.put("xor", "100110");

		// Halt
		mapaFunction.put("halt", "111111");

	}

	private void mapeiaTipoDaInstrucao() {

		mapaTipoInstrucao.put("000000", TIPO_R);

		mapaTipoInstrucao.put("001000", TIPO_I);
		mapaTipoInstrucao.put("001001", TIPO_I);
		mapaTipoInstrucao.put("001100", TIPO_I);
		mapaTipoInstrucao.put("000100", TIPO_I);
		mapaTipoInstrucao.put("000001", TIPO_I);
		mapaTipoInstrucao.put("000111", TIPO_I);
		mapaTipoInstrucao.put("000110", TIPO_I);
		mapaTipoInstrucao.put("000001", TIPO_I);
		mapaTipoInstrucao.put("000101", TIPO_I);
		mapaTipoInstrucao.put("100000", TIPO_I);
		mapaTipoInstrucao.put("100100", TIPO_I);
		mapaTipoInstrucao.put("100001", TIPO_I);
		mapaTipoInstrucao.put("100101", TIPO_I);
		mapaTipoInstrucao.put("001111", TIPO_I);
		mapaTipoInstrucao.put("100011", TIPO_I);
		mapaTipoInstrucao.put("110001", TIPO_I);
		mapaTipoInstrucao.put("001101", TIPO_I);
		mapaTipoInstrucao.put("101000", TIPO_I);
		mapaTipoInstrucao.put("001010", TIPO_I);
		mapaTipoInstrucao.put("001011", TIPO_I);
		mapaTipoInstrucao.put("101001", TIPO_I);
		mapaTipoInstrucao.put("101011", TIPO_I);
		mapaTipoInstrucao.put("111001", TIPO_I);
		mapaTipoInstrucao.put("001110", TIPO_I);

		mapaTipoInstrucao.put("000010", TIPO_J);
		mapaTipoInstrucao.put("000011", TIPO_J);
	}

	private void criaMapaRegistradores() {

		mapaRegistradores.put("$zero", "00000");
		mapaRegistradores.put("$at", "00001");

		mapaRegistradores.put("$v0", "00010");
		mapaRegistradores.put("$v1", "00011");

		mapaRegistradores.put("$a0", "00100");
		mapaRegistradores.put("$a1", "00101");
		mapaRegistradores.put("$a2", "00110");
		mapaRegistradores.put("$a3", "00111");

		mapaRegistradores.put("$t0", "01000");
		mapaRegistradores.put("$t1", "01001");
		mapaRegistradores.put("$t2", "01010");
		mapaRegistradores.put("$t3", "01011");
		mapaRegistradores.put("$t4", "01100");
		mapaRegistradores.put("$t5", "01101");
		mapaRegistradores.put("$t6", "01110");
		mapaRegistradores.put("$t7", "01111");
		mapaRegistradores.put("$t8", "11000");
		mapaRegistradores.put("$t9", "11001");

		mapaRegistradores.put("$s0", "10000");
		mapaRegistradores.put("$s1", "10001");
		mapaRegistradores.put("$s2", "10010");
		mapaRegistradores.put("$s3", "10011");
		mapaRegistradores.put("$s4", "10100");
		mapaRegistradores.put("$s5", "10101");
		mapaRegistradores.put("$s6", "10110");
		mapaRegistradores.put("$s7", "10111");

		mapaRegistradores.put("$k0", "11010");
		mapaRegistradores.put("$k1", "11011");

		mapaRegistradores.put("$gp", "11100");

		mapaRegistradores.put("$sp", "11101");

		mapaRegistradores.put("$fp", "11110");

		mapaRegistradores.put("$ra", "11111");
	}

}
